/*
 *  Copyright 2008 Mark Ashworth <javameme@gmail.com>.
 * 
 *  Licensed under the GNU General Public License v3 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *       http://www.gnu.org/licenses/gpl-3.0.html
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
package xperiment.metaphor.service.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import xperiment.metaphor.persistence.Dao;
import xperiment.metaphor.persistence.filter.Query;
import xperiment.metaphor.persistence.filter.SearchCriteria;
import xperiment.metaphor.service.DomainService;
import xperiment.metaphor.service.action.PersistAction;

/**
 * Abstract domain service implementing the basic functionality required by all 
 * domain service classes
 * @author Mark Ashworth <javameme@gmail.com>
 * @version 1.0.0
 */
public abstract class AbstractDomainService implements DomainService {
    /* Logger */
    protected Logger logger = LoggerFactory.getLogger(getClass());
    
    /* The domain access object for the service */
    private Dao dao;
    
    /* Persist actions */
    private Collection<PersistAction> persistActions = new ArrayList<PersistAction>();
    
    /**
     * The domain access object for the service
     * @return Dao
     */
    public Dao getDao() {
        return dao;
    }
    
    /**
     * The domain access object for the service
     * @param dao The new value
     */
    public void setDao(Dao dao) {
        this.dao = dao;
    }

    /**
     * Adds a persist action to be called before and after the object has been
     * persisted to the persistence store. This could be used for example to 
     * encode the password just before persisted to the store.<br />
     * 
     * The order that the actions are added, is the order that the actions
     * are executed.
     * 
     * @param persistAction The persist action to be performed
     */
    @Override
    public void addPersistAction(PersistAction persistAction) {
        if (this.persistActions == null) {
            this.persistActions = new ArrayList<PersistAction>();
        }
        this.persistActions.add(persistAction);
    }

    /**
     * Removes the persist action
     * @param persistAction The persist action to remove
     */
    @Override
    public void removePersistAction(PersistAction persistAction) {
        if (this.persistActions == null) {
            this.persistActions = new ArrayList<PersistAction>();
        }
        this.persistActions.remove(persistAction);
    }
    
    /**
     * Sets the persist actions
     * @param persistActions The new value
     */
    @Override
    public void setPersistActions(Collection<PersistAction> persistActions) {
        this.persistActions = persistActions;
    }
    
    /**
     * Returns the persist actions
     * @return Collection
     */
    @Override
    public Collection<PersistAction> getPersistActions() {
        return this.persistActions;
    }
    
    /**
     * Retrieve the complete list of objects
     * @return List
     */
    @Override
    @Transactional(readOnly=true)
    public List retrieve(Class persistentClass) {
        return getDao().retrieve(persistentClass);
    }
    
    /**
     * Retrieve the domain objects by search criteria
     * @param searchCriteria The search criteria
     * @return List
     */
    @Override
    @Transactional(readOnly=true)
    public List retrieve(SearchCriteria searchCriteria) {
        return getDao().retrieve(searchCriteria);
    }
    
    /**
     * Retrieve the domain objects by a query
     * @param query The query
     * @return List
     */
    @Override
    @Transactional(readOnly=true)
    public List retrieve(Query query) {
        return getDao().retrieve(query);
    }
    
    @Override
    @Transactional(readOnly=true)
    public Object retrieveById(Class persistentClass, Serializable id) {
        return getDao().retrieveById(persistentClass, id);
    }
    
    @Override
    @Transactional(readOnly=false)
    public Object save(Object object) {
        
        for (PersistAction persistAction : persistActions) {
            try {
                object = persistAction.before(object);
            } catch (Exception e) {
                logger.warn("Before persist action error", e);
            }
        }
        
        object = getDao().persist(object);
        
        for (PersistAction persistAction : persistActions) {
            try {
                object = persistAction.after(object);
            } catch (Exception e) {
                logger.warn("After persist action error", e);
            }
        }
        
        return object;
    }

    @Override
    @Transactional(readOnly=false)
    public void delete(Object object) {
        getDao().delete(object);
    }

    @Override
    @Transactional(readOnly=false)
    public void delete(List<Object> objects) {
        getDao().delete(objects);
    }
}
